

/***
 * @Date            : 2024-12-22 17:30:43
 * @Author          : AnimateX(Baron)
 * @LastEditors     : AnimateX(Baron)
 * @LastEditTime    : 2024-12-22 17:30:55
 * @FilePath        : /include/frame_capture.h
 * @CopyRight       : Copyright (c) 2025 AnimateX. All rights reserved.
 * @Description     :
 */
#pragma once
#include "camera.h"
#include "common_log.h"
#include "ringbuffer.h"
#include "preprocess.h"
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <mutex>
#include <atomic>
#include <string>
#include <thread>
#include <condition_variable>
#include <vector>


namespace rc {

    enum DataType {
        U8,
        U16,
        U32
    };

    struct Frame {
        std::unique_ptr<uint8_t[]>  data;
        uint64_t                    timeStamp;
        int                         width;
        int                         height;
        int                         channel;
        DataType                    dataType;

        // Add move constructor
        Frame(Frame&&) = default;
        Frame& operator=(Frame&&) = default;

        // Forbid copy
        Frame(const Frame&) = delete;
        Frame& operator=(const Frame&) = delete;
    };


    struct CameraConfig {
        std::string     uvcName;
        int             width;
        int             height;
        int             channel;
        DataType        dataType;
        uint32_t        pixelFormat;
        int             fps;
    };


    class FrameCapture {
    public:
        enum class Status {
            UNINITIALIZED,
            INITIALIZED,
            RUNNING,
            STOPPED,
            ERROR
        };

    private:
        Status status = Status::UNINITIALIZED;

        V4LCamera                           camera;
        std::thread                         producerThread_;
        std::size_t                         cpacity_;
        std::mutex                          mutex_;
        std::condition_variable             cv_;
        std::atomic<bool>                   stop_;
        std::unique_ptr<RingBuffer<Frame>>  frameBuffer_;
        std::string                         lastError_;
        CameraConfig                        defaultCfg_;

    public:
        explicit FrameCapture(size_t capcity, size_t imageSize, const std::string devName)
            : camera(devName)
            , cpacity_(capcity)
            , stop_(false) {
            frameBuffer_ = std::make_unique<RingBuffer<Frame>>(capcity, imageSize);
        }

        ~FrameCapture() {
            stop();
        }

        // capture frame data by uvc, save data to RingBuffer
        void producer() {
            std::vector<uint8_t> frameData;
            while (!stop_) {
                if (camera.captureFrame(frameData)) {
                    if (defaultCfg_.uvcName.find("RGB") != std::string::npos) {
                        rgbFrameTimeStamp rgbTimeStamp = { 0, 0, 0, 0 };
                        bool state = parserRgbFrameTimeStamp(frameData.data(), &rgbTimeStamp, frameData.size());

                        // decode move to consumer part.


                        // Construct Frame
                        Frame rgbFrame;
                        rgbFrame.data = std::make_unique<uint8_t>(Args &&args...)

                    }

                }
            }
        }

        // get frame from queue
        void tryPop(Frame& frame, std::chrono::milliseconds timeout) {

        }

        // config v4l2 param, initial ringbuffer???
        bool initialize(CameraConfig camCfg) {
            RCLogger& logger = RCLogger::getInstance();

            // [01] Check status
            if (status != Status::UNINITIALIZED) {
                lastError_ = " FrameCapture is already initialized.";
                logger.rs_error(" [Error] {}", lastError_);
                return false;
            }

            // Setting config.
            defaultCfg_ = camCfg;

            // [02] Initial v4l camera
            if (!camera.initialize(camCfg.width, camCfg.height, camCfg.pixelFormat, camCfg.fps)) {
                lastError_ = " Failed initial v4l-camera.";
                logger.rs_error(" [Error] {}: {}", lastError_, camCfg.uvcName);
                return false;
            }

            // [03] Initial RingBuffer
            size_t imageSize = camCfg.width * camCfg.height * camCfg.channel * (camCfg.dataType == DataType::U8 ? 1 : 2);
            frameBuffer_ = std::make_unique<RingBuffer<Frame>>(cpacity_, imageSize);

            status = Status::INITIALIZED;
            return true;
        }

        // start streaming, config produce/consumer thread
        bool start() {
            RCLogger& logger = RCLogger::getInstance();

            if (status != Status::INITIALIZED) {
                lastError_ = " Failed start streaming, please initialize FrameCapture";
                logger.rs_error(" [Error] {}.", lastError_);
                return false;
            }

            if (camera.startStreaming()) {
                lastError_ = " Failed start streaming";
                logger.rs_error(" [Error] {}.", lastError_);
                return false;
            }

            stop_ = false;
            producerThread_ = std::thread(&FrameCapture::producer, this);

            status = Status::RUNNING;
            return true;
        }

        // stop streaming --> await thread --> stop thread, clear queue
        void stop() {
            RCLogger& logger = RCLogger::getInstance();

            if (status == Status::STOPPED) {
                lastError_ = " FrameCapture already stopped";
                logger.rs_error(" [Errror] {}.", lastError_);
                return;
            }

            stop_ = true;
            if (producerThread_.joinable()) {
                producerThread_.join();
            }

            camera.stopStreaming();
            frameBuffer_->clear();

            status = Status::STOPPED;
        }

        Status getStatus() const { return status; }

    };
}
